Modifying a Template in Python

Community templates offers large varity from Azure QuickStart Templates (four hundreds templates) and enables one-click Azure service deployments by importing existing templates yet modifications are required to have customized infrastructure with particular configurations.

Simple Azure allows you to write/edit a template in Python with an editor package (python-editor). The changed template can be saved for future use by an export function.

Example: Changing 101-vm-sshkey template to deploy 3 VMs

In the previous tutorial, 101-vm-sshkey template was introduced to deploy a Ubuntu VM with a ssh key from Azure QuickStart Templates. Now, we may want to deploy three VMs using the template therefore a VM image and size are identical within a same virtual network. This also may help install hadoop clusters, for example if we want to setup NIST Fingerprint Matching with Apache Drill and HBase. Deploying software stacks on top of multiple VMs will be explained in the next tutorial.

Load 101-vm-sshkey template

First step is to load a 101-vm-sshkey template to make changes.


In [1]:
from simpleazure import SimpleAzure

In [ ]:
import os
os.environ['AZURE_SUBSCRIPTION_ID'] = $sid
os.environ['AZURE_CLIENT_SECRET'] = $password
os.environ['AZURE_TENANT_ID'] = $tid
os.environ['AZURE_CLIENT_ID'] = $cid

In [3]:
saz = SimpleAzure()
vm_sshkey = saz.aqst.get_template('101-vm-sshkey')

Edit a Template using System's Editor

Editor module provides an interface to modify your JSON template via System's editor e.g. vim, nano or emacs. The following function edit() opens an editor in your python although it is not supported in IPython Notebook. Screenshot is attached instead.


In [11]:
# This call is valid on a python interactive shell, not on IPython Notebook
# updated_vm_sshkey = vm_sshkey.edit()

Multiple Instances using Azure Template Iteration Function

Azure Template offers copy loop function to iterate resource items in Template. This is useful if we want to create multiple instances with a same properties e.g. VM image and size but different names with index. We will try to use the copy loop in this tutorial to create three VM instances from the 101-vm-sshkey base template. For more information, see the documenation here.

Resources to be changed

A VM (Microsoft.Compute/virtualMachines) starts with a network interface (Microsoft.Network/networkInterfaces) and a public IP address (Microsoft.Network/publicIPAddresses) in this template where the copy loop is also applied.

  • Microsoft.Compute/virtualMachines
  • Microsoft.Network/networkInterfaces
  • Microsoft.Network/publicIPAddresses

For your convenience, updated template is provided in the files folder. If you'd like to see the template, try to run this in ipython cell:

  • %load /home/jovyan/work/files/101-vm-sshkey-for-3vms.json

Resource not to be changed

The following resources are not changed as one resource is shared:

- Microsoft.Network/networkSecurityGroups
- Microsoft.Network/virtualNetworks

Diff Two Templates

To quickly review changes, a helper function is provided for a template comparison.

[template object].diff() function compares two templates and shows differences. Before we compare the original vm_sshkey (101-vm-sshkey) and the new updated_vm_sshkey (101-vm-sshkey-for-3vms) templates, we load the updated template from a file in this tutorial. This can be skipped if you manually updated the original template using a system editor with edit() function. The updated template is identical to the 101-vm-sshkey template except deploying 3 vms.


In [65]:
from simpleazure.template.template import Template
updated_vm_sshkey = Template()
updated_vm_sshkey.read_template("/home/jovyan/work/files/101-vm-sshkey-for-3vms.json")

Provide the update template object to the original using diff method. Output is similar to system diff command.


In [32]:
vm_sshkey.diff(updated_vm_sshkey)


--- a
+++ b
{
 'azuredeploy': {
  u'$schema': u'http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json',
  u'contentVersion': u'1.0.0.0',
  u'outputs': {u'sshCommand': {u'type': u'string', u'value': u"[concat('ssh ', parameters('adminUsername'), '@', variables('uniqueDnsLabelPrefix'), '.', resourceGroup().location, '.cloudapp.azure.com')]"}},
  u'parameters': {
   u'adminUserName': {u'defaultValue': u'azureuser', u'type': u'string', u'metadata': {u'description': u'User name for the Virtual Machine.'}},
  +u'numberOfInstances': {u'defaultValue': 3, u'type': u'int', u'metadata': {u'description': u'Number of Instances to start'}},
  @@  @@
  },
  u'resources': [
  @@ -4,1 +4,1 @@
  @@  @@
  @@ -4,0 +4,0 @@
     {
    u'apiVersion': u"[variables('apiVersion')]",
   +u'copy': {u'count': u"[parameters('numberOfInstances')]", u'name': u'ipLoop'},
    u'location': u"[variables('location')]",
   -u'name': u"[variables('publicIPAddressName')]",
   +u'name': u"[concat(variables('publicIPAddressName'), copyindex())]",
    u'properties': {
     u'dnsSettings': {
     -u'domainNameLabel': u"[variables('uniqueDnsLabelPrefix')]",
     +u'domainNameLabel': u"[concat(variables('uniqueDnsLabelPrefix'), copyindex())]",
     @@  @@
     },
     u'publicIPAllocationMethod': u"[variables('publicIPAddressType')]",
    @@  @@
    },
    u'type': u'Microsoft.Network/publicIPAddresses',
   @@  @@
   },
  @@  @@
  @@ -6,5 +6,5 @@
     {
    u'apiVersion': u"[variables('apiVersion')]",
   +u'copy': {u'count': u"[parameters('numberOfInstances')]", u'name': u'nicLoop'},
    u'dependsOn': [
    @@ -0 +0 @@
    -u"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
    +u"[concat('Microsoft.Network/publicIPAddresses/', concat(variables('publicIPAddressName'), copyindex()))]",
    @@  @@
    ],
    u'location': u"[variables('location')]",
   -u'name': u"[variables('nicName')]",
   +u'name': u"[concat(variables('nicName'), copyindex())]",
    u'properties': {
     u'ipConfigurations': [
     @@ -0 +0 @@
           {
       u'name': u'ipconfig1',
       u'properties': {
        u'privateIPAllocationMethod': u'Dynamic',
        u'publicIPAddress': {
        -u'id': u"[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]",
        +u'id': u"[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'), copyindex()))]",
        @@  @@
        },
        u'subnet': {u'id': u"[variables('subnet1Ref')]"},
       @@  @@
       },
      @@  @@
      },
     ],
    @@  @@
    },
    u'type': u'Microsoft.Network/networkInterfaces',
   @@  @@
   },
     {
    u'apiVersion': u"[variables('apiVersion')]",
   +u'copy': {u'count': u"[parameters('numberOfInstances')]", u'name': u'virtualMachineLoop'},
    u'dependsOn': [
    @@ -5,0 +5,0 @@
    @@  @@
    @@ -5,1 +5,1 @@
    -u"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]",
    +u"[concat('Microsoft.Network/networkInterfaces/', concat(variables('nicName'), copyindex()))]",
    ],
    u'location': u"[variables('location')]",
   -u'name': u"[variables('vmName')]",
   +u'name': u"[concat(variables('vmName'), copyindex())]",
    u'properties': {
     u'hardwareProfile': {u'vmSize': u"[variables('vmSize')]"},
     u'networkProfile': {
      u'networkInterfaces': [
      @@ -0 +0 @@
             {
       -u'id': u"[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]",
       +u'id': u"[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'), copyindex()))]",
       @@  @@
       },
      ],
     @@  @@
     },
     u'osProfile': {
      u'adminUsername': u"[parameters('adminUserName')]",
     -u'computerName': u"[variables('vmName')]",
     +u'computerName': u"[concat(variables('vmName'), copyindex())]",
      u'linuxConfiguration': {u'ssh': {u'publicKeys': [{u'path': u"[variables('sshKeyPath')]", u'keyData': u"[parameters('sshKeyData')]"}]}, u'disablePasswordAuthentication': u'true'},
     @@  @@
     },
     u'storageProfile': {
      u'imageReference': {u'sku': u"[variables('ubuntuOSVersion')]", u'publisher': u"[variables('imagePublisher')]", u'version': u'latest', u'offer': u"[variables('imageOffer')]"},
      u'osDisk': {
       u'caching': u'ReadWrite',
       u'createOption': u'FromImage',
      -u'name': u'osdisk',
      +u'name': u"[concat('osdisk', copyindex())]",
       u'vhd': {
       -u'uri': u"[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', variables('osDiskName'),'.vhd')]",
       +u'uri': u"[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', variables('osDiskName'), copyindex(), '.vhd')]",
       @@  @@
       },
      @@  @@
      },
     @@  @@
     },
    @@  @@
    },
    u'type': u'Microsoft.Compute/virtualMachines',
   @@  @@
   },
  ],
 @@  @@
 },
 'etc': [],
 'metadata': {u'githubUsername': u'squillace', u'dateUpdated': u'2015-06-05', u'itemDisplayName': u'Deploy a Virtual Machine with SSH rsa public key', u'description': u'This template allows you to create a Virtual Machine with SSH rsa public key', u'summary': u'Deploy a Virtual Machine with SSH rsa public key'},
 'parameters': {
  u'$schema': u'http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#',
  u'contentVersion': u'1.0.0.0',
  u'parameters': {
  +u'numberOfInstances': {u'value': 3},
   u'sshKeyData': {
   -u'value': u'GEN-SSH-PUB-KEY',
   +u'value': u'ssh-rsa AAAAB...<skipped>... hroe.lee@simpleazure',
   @@  @@
   },
  @@  @@
  },
 },
 'scripts': '',
@@  @@
}

Review the lines with + and - where + indicates an updated line and - indicates an original line.

For example, a new parameter numberOfInstances is added to specify a number of vms to start, 3 is given in this example to produce 3 vms. (find the numberOfInstances at the last part of the content )

The resources- virtualMachines, networkInterfaces, and publicIPAddresses- are now described with copy loop function to iterate a resource creation witn an index for unique name (copyindex() is used for index). For example, virtualMachine names are described with template functions: concat( [variables('vmName')], copyindex()) and actual values are like sshvm1, sshvm2 and sshvm3.

Number of virtual machines

  • Original: 1 vm
  • Updated: 3 vms
  • Change:
    • +u'copy': {u'count': u"[parameters('numberOfInstances')]", u'name': u'virtualMachineLoop'},

Virtual machine Names

  • Original: sshvm
  • Updated: sshvm1, sshvm2, sshvm3
  • Change:
    • -u'name': u"[variables('vmName')]",
    • +u'name': u"[concat(variables('vmName'), copyindex())]",

Public IP address names

  • Original: sshPublicIP
  • Updated: sshPublicIP1, sshPublicIP2, sshPublicIP3
  • Change:
    • -u'name': u"[variables('publicIPAddressName')]",
    • +u'name': u"[concat(variables('publicIPAddressName'), copyindex())]",

Network interface names

  • Original: sshNIC
  • Updated: sshNIC1, sshNIC2, sshNIC3
  • change:
    • -u'name': u"[variables('nicName')]",
    • +u'name': u"[concat(variables('nicName'), copyindex())]",

Similar changes are made towards networkInterfaces and publicIPAddresses because these resources depend on virual machines.

Load Updated Template for ARM

The updated template (updated_vm_sshkey) is ready to deploy 3 vms. Let's use Azure Resource Manager (ARM) in Simple Azure.

Note: template validation is not supported in the current version.


In [66]:
saz.arm.load_template(updated_vm_sshkey)

Confirm Paramters

Just to make sure what parameters are given. For example, review login username (adminUsername) and public ssh key string (sshKeyData).


In [67]:
saz.arm.parameters


Out[67]:
{u'adminUsername': {u'value': u'azureuser'},
 u'numberOfInstances': {u'value': 3},
 u'sshKeyData': {u'value': u'ssh-rsa AAAAB...<skipped>... hroe.lee@simpleazure'}}

Update Parameter

Let's change a login user name to 'simpleazure' just for a practice.


In [68]:
saz.arm.add_parameter({"adminUsername":'simpleazure'})


Out[68]:
{u'adminUsername': {u'value': 'simpleazure'},
 u'numberOfInstances': {u'value': 3},
 u'sshKeyData': {u'value': u'ssh-rsa AAAAB...<skipped>... hroe.lee@simpleazure'}}

Remember, simpleazure login name will be used in SSH client.

Deploy New Version

It's time to deploy 3 VMs using the updated template. Just wait and see its deployment. It may take 2-3 minutes.


In [40]:
saz.arm.deploy()


214.69 elapsed time for the deployment
Out[40]:
<msrestazure.azure_operation.AzureOperationPoller at 0x7fd7948b8dd0>

It took about 3 minutes and deployed resources are also visible at the portal.

Access Information

Public IP addresses are provided to get access launched VMs.


In [52]:
saz.arm.view_info()


Out[52]:
[u'40.77.67.172', u'104.208.36.189', u'40.77.71.155']

Sample SSH Access

$ ssh simpleazure@40.77.67.172
The authenticity of host '40.77.67.172 (40.77.67.172)' can't be established.
ECDSA key fingerprint is ec:98:eb:c9:eb:2c:b5:f2:b3:9e:64:36:d1:b4:38:2b.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '40.77.67.172' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 14.04.4 LTS (GNU/Linux 3.19.0-65-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

  System information as of Thu Oct 27 04:58:18 UTC 2016

  System load: 0.39              Memory usage: 1%   Processes:       90
  Usage of /:  39.6% of 1.94GB   Swap usage:   0%   Users logged in: 0

  Graph this data and manage this system at:
    https://landscape.canonical.com/

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

0 packages can be updated.
0 updates are security updates.



The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

simpleazure@sshvm0:~$

Export Template

Simple Azure allows you to save your new template therefore it can be used for the future deployments. Or additional changes can be made from the updated template, for example, customscript to run initial script.

Note: customscript is Azure Extensions to run a script after its provisioning. See more from documentation or example

export_template() returns a loaded template from ARM object.


In [69]:
saz.arm.export_template()


Out[69]:
{u'azuredeploy': {u'$schema': u'http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json',
  u'contentVersion': u'1.0.0.0',
  u'outputs': {u'sshCommand': {u'type': u'string',
    u'value': u"[concat('ssh ', parameters('adminUsername'), '@', variables('uniqueDnsLabelPrefix'), '.', resourceGroup().location, '.cloudapp.azure.com')]"}},
  u'parameters': {u'adminUserName': {u'defaultValue': u'azureuser',
    u'metadata': {u'description': u'User name for the Virtual Machine.'},
    u'type': u'string'},
   u'numberOfInstances': {u'defaultValue': 3,
    u'metadata': {u'description': u'Number of Instances to start'},
    u'type': u'int'},
   u'sshKeyData': {u'metadata': {u'description': u'SSH rsa public key file as a string.'},
    u'type': u'string'}},
  u'resources': [{u'apiVersion': u"[variables('apiVersion')]",
    u'location': u"[variables('location')]",
    u'name': u"[variables('storageAccountName')]",
    u'properties': {u'accountType': u"[variables('storageAccountType')]"},
    u'type': u'Microsoft.Storage/storageAccounts'},
   {u'apiVersion': u"[variables('apiVersion')]",
    u'location': u"[variables('location')]",
    u'name': u"[variables('networkSecurityGroupName')]",
    u'properties': {u'securityRules': [{u'name': u'ssh_rule',
       u'properties': {u'access': u'Allow',
        u'description': u'Locks inbound down to ssh default port 22.',
        u'destinationAddressPrefix': u'*',
        u'destinationPortRange': u'22',
        u'direction': u'Inbound',
        u'priority': 123,
        u'protocol': u'Tcp',
        u'sourceAddressPrefix': u'*',
        u'sourcePortRange': u'*'}}]},
    u'type': u'Microsoft.Network/networkSecurityGroups'},
   {u'apiVersion': u"[variables('apiVersion')]",
    u'copy': {u'count': u"[parameters('numberOfInstances')]",
     u'name': u'ipLoop'},
    u'location': u"[variables('location')]",
    u'name': u"[concat(variables('publicIPAddressName'), copyindex())]",
    u'properties': {u'dnsSettings': {u'domainNameLabel': u"[concat(variables('uniqueDnsLabelPrefix'), copyindex())]"},
     u'publicIPAllocationMethod': u"[variables('publicIPAddressType')]"},
    u'type': u'Microsoft.Network/publicIPAddresses'},
   {u'apiVersion': u"[variables('apiVersion')]",
    u'dependsOn': [u"[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]"],
    u'location': u"[variables('location')]",
    u'name': u"[variables('virtualNetworkName')]",
    u'properties': {u'addressSpace': {u'addressPrefixes': [u"[variables('addressPrefix')]"]},
     u'subnets': [{u'name': u"[variables('subnet1Name')]",
       u'properties': {u'addressPrefix': u"[variables('subnet1Prefix')]",
        u'networkSecurityGroup': {u'id': u"[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"}}}]},
    u'type': u'Microsoft.Network/virtualNetworks'},
   {u'apiVersion': u"[variables('apiVersion')]",
    u'copy': {u'count': u"[parameters('numberOfInstances')]",
     u'name': u'nicLoop'},
    u'dependsOn': [u"[concat('Microsoft.Network/publicIPAddresses/', concat(variables('publicIPAddressName'), copyindex()))]",
     u"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"],
    u'location': u"[variables('location')]",
    u'name': u"[concat(variables('nicName'), copyindex())]",
    u'properties': {u'ipConfigurations': [{u'name': u'ipconfig1',
       u'properties': {u'privateIPAllocationMethod': u'Dynamic',
        u'publicIPAddress': {u'id': u"[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'), copyindex()))]"},
        u'subnet': {u'id': u"[variables('subnet1Ref')]"}}}]},
    u'type': u'Microsoft.Network/networkInterfaces'},
   {u'apiVersion': u"[variables('apiVersion')]",
    u'copy': {u'count': u"[parameters('numberOfInstances')]",
     u'name': u'virtualMachineLoop'},
    u'dependsOn': [u"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
     u"[concat('Microsoft.Network/networkInterfaces/', concat(variables('nicName'), copyindex()))]"],
    u'location': u"[variables('location')]",
    u'name': u"[concat(variables('vmName'), copyindex())]",
    u'properties': {u'hardwareProfile': {u'vmSize': u"[variables('vmSize')]"},
     u'networkProfile': {u'networkInterfaces': [{u'id': u"[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'), copyindex()))]"}]},
     u'osProfile': {u'adminUsername': u"[parameters('adminUserName')]",
      u'computerName': u"[concat(variables('vmName'), copyindex())]",
      u'linuxConfiguration': {u'disablePasswordAuthentication': u'true',
       u'ssh': {u'publicKeys': [{u'keyData': u"[parameters('sshKeyData')]",
          u'path': u"[variables('sshKeyPath')]"}]}}},
     u'storageProfile': {u'imageReference': {u'offer': u"[variables('imageOffer')]",
       u'publisher': u"[variables('imagePublisher')]",
       u'sku': u"[variables('ubuntuOSVersion')]",
       u'version': u'latest'},
      u'osDisk': {u'caching': u'ReadWrite',
       u'createOption': u'FromImage',
       u'name': u"[concat('osdisk', copyindex())]",
       u'vhd': {u'uri': u"[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', variables('osDiskName'), copyindex(), '.vhd')]"}}}},
    u'type': u'Microsoft.Compute/virtualMachines'}],
  u'variables': {u'addressPrefix': u'10.0.0.0/16',
   u'apiVersion': u'2015-06-15',
   u'imageOffer': u'UbuntuServer',
   u'imagePublisher': u'Canonical',
   u'location': u'[resourceGroup().location]',
   u'networkSecurityGroupName': u'networkSecurityGroup1',
   u'nicName': u'sshNIC',
   u'osDiskName': u'osDisk1',
   u'publicIPAddressName': u'sshPublicIP',
   u'publicIPAddressType': u'Dynamic',
   u'sshKeyPath': u"[concat('/home/',parameters('adminUserName'),'/.ssh/authorized_keys')]",
   u'storageAccountName': u"[concat(uniquestring(resourceGroup().id), 'sasshvm')]",
   u'storageAccountType': u'Premium_LRS',
   u'subnet1Name': u'Subnet-1',
   u'subnet1Prefix': u'10.0.0.0/24',
   u'subnet1Ref': u"[concat(variables('vnetID'),'/subnets/',variables('subnet1Name'))]",
   u'ubuntuOSVersion': u'14.04.4-LTS',
   u'uniqueDnsLabelPrefix': u"[concat('store', uniquestring(resourceGroup().id))]",
   u'virtualNetworkName': u'sshVNET',
   u'vmName': u'sshvm',
   u'vmSize': u'Standard_DS2',
   u'vmStorageAccountContainerName': u'vhds',
   u'vnetID': u"[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"}},
 u'etc': [],
 u'metadata': {u'dateUpdated': u'2015-06-05',
  u'description': u'This template allows you to create a Virtual Machine with SSH rsa public key',
  u'githubUsername': u'squillace',
  u'itemDisplayName': u'Deploy a Virtual Machine with SSH rsa public key',
  u'summary': u'Deploy a Virtual Machine with SSH rsa public key'},
 u'nested': u'',
 u'parameters': {u'$schema': u'http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#',
  u'contentVersion': u'1.0.0.0',
  u'parameters': {u'adminUsername': {u'value': 'simpleazure'},
   u'numberOfInstances': {u'value': 3},
   u'sshKeyData': {u'value': u'ssh-rsa AAAAB...<skipped>... hroe.lee@simpleazure'}}},
 u'scripts': u''}

export_template() returns Simple Azure Template class object.

Therefore if you'd like to obtain a deploy template only (like azuredeploy.json), then use ['azuredeploy'] like:


In [71]:
saz.arm.export_template()['azuredeploy']


Out[71]:
{u'$schema': u'http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json',
 u'contentVersion': u'1.0.0.0',
 u'outputs': {u'sshCommand': {u'type': u'string',
   u'value': u"[concat('ssh ', parameters('adminUsername'), '@', variables('uniqueDnsLabelPrefix'), '.', resourceGroup().location, '.cloudapp.azure.com')]"}},
 u'parameters': {u'adminUserName': {u'defaultValue': u'azureuser',
   u'metadata': {u'description': u'User name for the Virtual Machine.'},
   u'type': u'string'},
  u'numberOfInstances': {u'defaultValue': 3,
   u'metadata': {u'description': u'Number of Instances to start'},
   u'type': u'int'},
  u'sshKeyData': {u'metadata': {u'description': u'SSH rsa public key file as a string.'},
   u'type': u'string'}},
 u'resources': [{u'apiVersion': u"[variables('apiVersion')]",
   u'location': u"[variables('location')]",
   u'name': u"[variables('storageAccountName')]",
   u'properties': {u'accountType': u"[variables('storageAccountType')]"},
   u'type': u'Microsoft.Storage/storageAccounts'},
  {u'apiVersion': u"[variables('apiVersion')]",
   u'location': u"[variables('location')]",
   u'name': u"[variables('networkSecurityGroupName')]",
   u'properties': {u'securityRules': [{u'name': u'ssh_rule',
      u'properties': {u'access': u'Allow',
       u'description': u'Locks inbound down to ssh default port 22.',
       u'destinationAddressPrefix': u'*',
       u'destinationPortRange': u'22',
       u'direction': u'Inbound',
       u'priority': 123,
       u'protocol': u'Tcp',
       u'sourceAddressPrefix': u'*',
       u'sourcePortRange': u'*'}}]},
   u'type': u'Microsoft.Network/networkSecurityGroups'},
  {u'apiVersion': u"[variables('apiVersion')]",
   u'copy': {u'count': u"[parameters('numberOfInstances')]",
    u'name': u'ipLoop'},
   u'location': u"[variables('location')]",
   u'name': u"[concat(variables('publicIPAddressName'), copyindex())]",
   u'properties': {u'dnsSettings': {u'domainNameLabel': u"[concat(variables('uniqueDnsLabelPrefix'), copyindex())]"},
    u'publicIPAllocationMethod': u"[variables('publicIPAddressType')]"},
   u'type': u'Microsoft.Network/publicIPAddresses'},
  {u'apiVersion': u"[variables('apiVersion')]",
   u'dependsOn': [u"[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]"],
   u'location': u"[variables('location')]",
   u'name': u"[variables('virtualNetworkName')]",
   u'properties': {u'addressSpace': {u'addressPrefixes': [u"[variables('addressPrefix')]"]},
    u'subnets': [{u'name': u"[variables('subnet1Name')]",
      u'properties': {u'addressPrefix': u"[variables('subnet1Prefix')]",
       u'networkSecurityGroup': {u'id': u"[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]"}}}]},
   u'type': u'Microsoft.Network/virtualNetworks'},
  {u'apiVersion': u"[variables('apiVersion')]",
   u'copy': {u'count': u"[parameters('numberOfInstances')]",
    u'name': u'nicLoop'},
   u'dependsOn': [u"[concat('Microsoft.Network/publicIPAddresses/', concat(variables('publicIPAddressName'), copyindex()))]",
    u"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"],
   u'location': u"[variables('location')]",
   u'name': u"[concat(variables('nicName'), copyindex())]",
   u'properties': {u'ipConfigurations': [{u'name': u'ipconfig1',
      u'properties': {u'privateIPAllocationMethod': u'Dynamic',
       u'publicIPAddress': {u'id': u"[resourceId('Microsoft.Network/publicIPAddresses', concat(variables('publicIPAddressName'), copyindex()))]"},
       u'subnet': {u'id': u"[variables('subnet1Ref')]"}}}]},
   u'type': u'Microsoft.Network/networkInterfaces'},
  {u'apiVersion': u"[variables('apiVersion')]",
   u'copy': {u'count': u"[parameters('numberOfInstances')]",
    u'name': u'virtualMachineLoop'},
   u'dependsOn': [u"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
    u"[concat('Microsoft.Network/networkInterfaces/', concat(variables('nicName'), copyindex()))]"],
   u'location': u"[variables('location')]",
   u'name': u"[concat(variables('vmName'), copyindex())]",
   u'properties': {u'hardwareProfile': {u'vmSize': u"[variables('vmSize')]"},
    u'networkProfile': {u'networkInterfaces': [{u'id': u"[resourceId('Microsoft.Network/networkInterfaces', concat(variables('nicName'), copyindex()))]"}]},
    u'osProfile': {u'adminUsername': u"[parameters('adminUserName')]",
     u'computerName': u"[concat(variables('vmName'), copyindex())]",
     u'linuxConfiguration': {u'disablePasswordAuthentication': u'true',
      u'ssh': {u'publicKeys': [{u'keyData': u"[parameters('sshKeyData')]",
         u'path': u"[variables('sshKeyPath')]"}]}}},
    u'storageProfile': {u'imageReference': {u'offer': u"[variables('imageOffer')]",
      u'publisher': u"[variables('imagePublisher')]",
      u'sku': u"[variables('ubuntuOSVersion')]",
      u'version': u'latest'},
     u'osDisk': {u'caching': u'ReadWrite',
      u'createOption': u'FromImage',
      u'name': u"[concat('osdisk', copyindex())]",
      u'vhd': {u'uri': u"[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', variables('osDiskName'), copyindex(), '.vhd')]"}}}},
   u'type': u'Microsoft.Compute/virtualMachines'}],
 u'variables': {u'addressPrefix': u'10.0.0.0/16',
  u'apiVersion': u'2015-06-15',
  u'imageOffer': u'UbuntuServer',
  u'imagePublisher': u'Canonical',
  u'location': u'[resourceGroup().location]',
  u'networkSecurityGroupName': u'networkSecurityGroup1',
  u'nicName': u'sshNIC',
  u'osDiskName': u'osDisk1',
  u'publicIPAddressName': u'sshPublicIP',
  u'publicIPAddressType': u'Dynamic',
  u'sshKeyPath': u"[concat('/home/',parameters('adminUserName'),'/.ssh/authorized_keys')]",
  u'storageAccountName': u"[concat(uniquestring(resourceGroup().id), 'sasshvm')]",
  u'storageAccountType': u'Premium_LRS',
  u'subnet1Name': u'Subnet-1',
  u'subnet1Prefix': u'10.0.0.0/24',
  u'subnet1Ref': u"[concat(variables('vnetID'),'/subnets/',variables('subnet1Name'))]",
  u'ubuntuOSVersion': u'14.04.4-LTS',
  u'uniqueDnsLabelPrefix': u"[concat('store', uniquestring(resourceGroup().id))]",
  u'virtualNetworkName': u'sshVNET',
  u'vmName': u'sshvm',
  u'vmSize': u'Standard_DS2',
  u'vmStorageAccountContainerName': u'vhds',
  u'vnetID': u"[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"}}

This does not include parameter settings that you specified e.g. adminUserame, numberOfInstances and sshKeyData.

Use ['parameters'] if you'd like to obtain a template for parameters like azuredeploy.parameters.json.


In [72]:
saz.arm.export_template()['parameters']


Out[72]:
{u'$schema': u'http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#',
 u'contentVersion': u'1.0.0.0',
 u'parameters': {u'adminUsername': {u'value': 'simpleazure'},
  u'numberOfInstances': {u'value': 3},
  u'sshKeyData': {u'value': u'ssh-rsa AAAAB...<skipped>... hroe.lee@simpleazure'}}}

Save to a File

Provide a filepath to store.


In [ ]:
saz.arm.export_template().save("/home/jovyan/work/files/updated_template_for_3vms.json")

Terminate All Resources

Removing a resource group deletes all deployed resources. Warning: it may cause other issues if you have multiple deployments.


In [70]:
saz.arm.remove_resource_group()


Out[70]:
<msrestazure.azure_operation.AzureOperationPoller at 0x7fd7932d1410>

Template is useful to reproduce infrastructure and Azure QuickStart Templates shares well developed community templates. Simple Azure offers Template loading/editing/exporting in Python therefore Azure Template users can use, modify and save their work on Templates.

Simple Azure is under development which means that new features are added constantly, please report any issues on Github and give any feedbacks to improve.

In the next tutorial, we will explore how to deploy software stacks after provisiong infrastructure. Ansible automation tool is also introduced.